package handler

import (
	"strconv"
	"trader/apps/common/resp"
	"trader/constant"
	"trader/models"
	"trader/service/stockapi"
	"trader/utils"

	"github.com/gin-gonic/gin"
	"xorm.io/xorm"
)

// StockHandler 封装所有Stock操作
type StockHandler struct {
	Engine *xorm.Engine
}

// NewStockHandler 创建新的Stock处理器
func NewStockHandler(engine *xorm.Engine) *StockHandler {
	return &StockHandler{Engine: engine}
}

type CreateStockRequest struct {
	Code string `json:"code" binding:"required"`
}

// Create 创建Stock
func (h *StockHandler) Create(c *gin.Context) {
	accountId := c.GetInt64("tradingAccountId")

	var req CreateStockRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		resp.FailParamf(c, "请求参数不合法：%v", err)
		return
	}

	exist, err := h.Engine.Exist(&models.Stock{Code: req.Code, TradingAccountId: accountId})
	if exist {
		resp.FailParamf(c, "已存在")
		return
	}

	// 验证Stock代码有效性
	api := stockapi.New()
	quote, err := api.SimpleQuote(req.Code)
	if err != nil {
		resp.FailParamf(c, "%v", err)
		return
	}

	exchange, _ := utils.VerifyStockCode(quote.Code)

	newStock := models.Stock{TradingAccountId: accountId, Code: quote.Code, Name: quote.Name, Exchange: exchange}
	_, err = h.Engine.Insert(&newStock)
	if err != nil {
		resp.FailDB(c, err)
		return
	}

	resp.OK(c, "添加成功", gin.H{"id": newStock.Id})
}

// Get 获取单个Stock
func (h *StockHandler) Get(c *gin.Context) {
	accountId, err := strconv.ParseInt(c.Param("trading_account_id"), 10, 64)
	if err != nil {
		resp.FailParamf(c, "无效参数")
		return
	}

	id, err := strconv.ParseInt(c.Param("stock_id"), 10, 64)
	if err != nil {
		resp.FailParamf(c, "无效的参数")
		return
	}

	var stock models.Stock
	has, err := h.Engine.Where("trading_account_id=? and id=?", accountId, id).Get(&stock)
	if err != nil {
		resp.FailDB(c, err)
		return
	}
	if !has {
		resp.FailParamf(c, "Stock 不存在")
		return
	}

	resp.OK(c, "ok", stock)
}

type StockUpdateRequest struct {
	Name string `json:"name" binding:"required"`
}

// Update 更新Stock
func (h *StockHandler) Update(c *gin.Context) {
	accountId := c.GetInt64("tradingAccountId")

	id, err := strconv.ParseInt(c.Param("stock_id"), 10, 64)
	if err != nil {
		resp.FailParamf(c, "无效的参数")
		return
	}

	var req StockUpdateRequest
	if err = c.ShouldBindJSON(&req); err != nil {
		resp.FailParamf(c, "参数验证失败：%v", err)
		return
	}

	// 执行更新
	affected, err := h.Engine.Table(new(models.Stock)).Where("trading_account_id=? and id=?", accountId, id).Cols("name").Update(map[string]any{"name": req.Name})
	if err != nil {
		resp.FailDB(c, err)
		return
	}
	if affected == 0 {
		resp.FailParamf(c, "Stock不存在或未更改")
		return
	}

	resp.OKWithoutData(c, "更新成功")
}

// Delete 删除Stock（软删除）todo: 是否删除关联资源？
func (h *StockHandler) Delete(c *gin.Context) {
	accountId := c.GetInt64("tradingAccountId")

	id, err := strconv.ParseInt(c.Param("stock_id"), 10, 64)
	if err != nil {
		resp.FailParamf(c, "无效的参数")
		return
	}

	// 使用Delete进行软删除
	affected, err := h.Engine.Where("trading_account_id=? and id=?", accountId, id).Delete(&models.Stock{})
	if err != nil {
		resp.FailDB(c, err)
		return
	}
	if affected == 0 {
		resp.FailParamf(c, "Stock 不存在")
		return
	}

	resp.OKWithoutData(c, "已删除")
}

// List 获取Stock列表
func (h *StockHandler) List(c *gin.Context) {
	accountId := c.GetInt64("tradingAccountId")

	page, err := strconv.ParseInt(c.DefaultQuery("page", "1"), 10, 64)
	if err != nil {
		page = 1
	}

	pageSize, err := strconv.ParseInt(c.DefaultQuery("page_size", "10"), 10, 64)
	if err != nil {
		pageSize = 10
	}

	query := h.Engine.Where("trading_account_id = ?", accountId)

	key := c.Query("key")
	if key != "" {
		query = query.And("code LIKE ? OR name LIKE ?", "%"+key+"%", "%"+key+"%")
	}

	stocks := make([]models.Stock, 0)
	total, err := query.OrderBy("-id").Limit(int(pageSize), int((page-1)*pageSize)).FindAndCount(&stocks)
	if err != nil {
		resp.FailDB(c, err)
		return
	}

	type respData struct {
		models.Stock
		PlanId     int64 `json:"planId"`
		PlanStatus int   `json:"planStatus"`
	}

	data := make([]respData, 0)
	for _, stock := range stocks {
		i := respData{Stock: stock, PlanStatus: constant.Null}

		plan := new(models.TransactionPlan)
		exist, _ := h.Engine.Where("trading_account_id = ? and stock_id = ?", accountId, stock.Id).OrderBy("-id").Get(plan)
		if exist {
			i.PlanId = plan.Id
			i.PlanStatus = plan.Status
		}
		data = append(data, i)
	}
	resp.OKPage(c, total, page, pageSize, data)
}
